package main

import (
	"fmt"
	"math/rand"
	"time"
)

/*
工作goroutine池可以避免goroutine的数量暴涨
类似于java的ThreadPoolExecutor，可以控制工作协程goroutine的数量

一个小案例，
	计算一个数字的各个位数之和，例如数字123，结果为1+2+3=6
	不停地随机生成数字进行计算


*/
func main() {
	// 创建两个channel
	jobChannel := make(chan *Job, 128)
	resultChannel := make(chan *Result, 128)

	createPool(64, jobChannel, resultChannel)

	// 遍历resultChannel，打印结果
	go func() {
		for result := range resultChannel {
			fmt.Printf("job id:%v randnum:%v result:%d\n",
				result.MyJob.Id,
				result.MyJob.RandNum, result.Ans)
		}
	}()

	// 使用一个协程，疯狂产生job
	go func() {
		id := 0
		for {
			job := &Job{
				Id:      id,
				RandNum: rand.Int(),
			}
			jobChannel <- job
			id++
		}
	}()

	// 主线程等待1分钟
	time.Sleep(1 * time.Minute)

}

type Job struct {
	Id      int // 当前job的id
	RandNum int // 随机数
}

type Result struct {
	MyJob *Job
	Ans   int // 计算结果
}

/**
size: 协程数量
jobChannel: 存放任务的队列
resultChannel: 存放每一个job结果的队列
*/
func createPool(size int, jobChannel chan *Job, resultChannel chan *Result) {
	for i := 0; i < size; i++ {
		go func() {
			// 从jobChannel中遍历获取一个job
			for job := range jobChannel {
				randNum := job.RandNum
				// 计算randNum的各位数字之和
				sum := 0
				for temp := randNum; temp > 0; temp /= 10 {
					sum += temp % 10
				}
				// 构造result并放入resultChannel
				result := new(Result)
				result.MyJob = job
				result.Ans = sum
				resultChannel <- result
			}

		}()
	}
}
